package com.example.Controller;

import com.example.Service.NetService;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.*;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import java.net.InetAddress;
import java.net.UnknownHostException;

import static com.example.Util.Utils.buildMessage; // 静态导入

public class Controller implements NetService.NetStateChange { // Controller 类实现 NetService.NetStateChange 接口中定义的所有抽象方法

    public static NetType netType; // 网络类型
    @FXML
    Canvas canvas; // 棋盘画布
    @FXML
    TextField tfIP; // IP输入框
    @FXML
    TextField tfMessage; // 消息输入框
    @FXML
    TextArea taContent; // 内容显示框
    @FXML
    Label lbIP; // IP标签
    @FXML
    Button btnConnect; // 连接按钮
    @FXML
    Button btnStart; // 开始游戏按钮
    @FXML
    Button btnSend; // 发送按钮
    @FXML
    Button btnUndo; // 悔棋按钮

    private Color colorChessboard = Color.valueOf("#FBE39B");
    private Color colorLine = Color.valueOf("#884B09");
    private Color colorMark = Color.valueOf("#FF7F27");
    private GraphicsContext gc;
    private double gapX, gapY;
    private double chessSize;
    private double broadPadding = 20;
    private String[] markX = new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U"};
    private String[] markY = new String[]{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21"};

    private NetService server; // 服务端
    private NetService client; // 玩家B

    // 消息头常量 用来区分消息类型
    static final String HEAD_NET = "net";
    static final String HEAD_MSG = "msg";
    static final String HEAD_CHESS = "chess";
    static final String HEAD_GAME = "game";
    static final String HEAD_UNDO = "undo";
    static final String BODY_OK = "ok";
    static final String BODY_NO = "no";

    private boolean isOtherOK = true;

    private Position lastPostion;

    private enum Chess {
        BLACK, WHITE
    }

    // 网络类型枚举类
    public enum NetType {
        SERVER, CLIENT
    }

    private enum Direction {
        TOP_LEFT, TOP, TOP_RIGHT, RIGHT, RIGHT_DOWN, DOWN, DOWN_LEFT, LEFT
    }


    private Chess currentChess;
    private Chess[][] game = new Chess[21][21];

    @FXML
    // 棋盘点击事件处理函数
    protected void handleCanvasClicked(MouseEvent event) {
        Position p = convertPosition(event.getX() - broadPadding, event.getY() - broadPadding);
        if (p.x < 0 || p.y < 0 || p.x > 20 || p.y > 20 || game[p.x][p.y] != null) {
            return;
        }
        // 服务器端
        if (netType == NetType.SERVER) {
            if (isOtherOK) { // 对方就绪
                if (currentChess == Chess.BLACK) { // 当前轮到黑棋（服务器）
                    drawChess(currentChess, p); // 绘制黑棋
                    server.sendMessage(buildMessage(HEAD_CHESS, p.toString())); // 发送走棋消息
                    taContent.appendText("[玩家A]走子：" + markX[p.x] + "," + markY[p.y] + "\n"); // 记录日志
                    currentChess = Chess.WHITE; // 切换为白棋（玩家B）
                    game[p.x][p.y] = Chess.BLACK; // 记录棋盘状态
                    lastPostion = p; // 记录最后一步
                    btnUndo.setDisable(false); // 启用悔棋按钮（从禁用状态变为可点击状态）
                    checkWinner(p.x, p.y); // 检查是否获胜
                } else {
                    taContent.appendText("[系统]请等待玩家B走棋！\n");
                }
            } else {
                taContent.appendText("[系统]玩家B还没有准备好！\n");
            }
        }
        // 玩家B
        else if (netType == NetType.CLIENT) {
            if (isOtherOK) {
                if (currentChess == Chess.WHITE) {
                    drawChess(currentChess, p);
                    client.sendMessage(buildMessage(HEAD_CHESS, p.toString()));
                    taContent.appendText("[玩家B]走子：" + markX[p.x] + "," + markY[p.y] + "\n");
                    currentChess = Chess.BLACK;
                    game[p.x][p.y] = Chess.WHITE;
                    lastPostion = p;
                    btnUndo.setDisable(false);
                    checkWinner(p.x, p.y);
                } else {
                    taContent.appendText("[系统]请等待玩家A走棋！\n");
                }
            } else {
                taContent.appendText("[系统]玩家A还没有准备好！\n");
            }
        }

    }

    // 将鼠标位置转换为棋盘坐标
    private Position convertPosition(double x, double y) {
        int pX = (int) ((x + gapX / 2) / gapX);
        int pY = (int) ((y + gapY / 2) / gapY);
        return new Position(pX, pY);
    }

    // 检查是否胜利
    private void checkWinner(int x, int y) {
        Chess thisChess = game[x][y];
        if (thisChess == null) {
            return;
        }

        int left2Right = 1 + countChessNum(Direction.LEFT, thisChess, x, y) + countChessNum(Direction.RIGHT, thisChess, x, y);
        System.out.println("--" + left2Right);
        if (left2Right >= 5) {
            win(thisChess);
            return;
        }

        int top2Down = 1 + countChessNum(Direction.TOP, thisChess, x, y) + countChessNum(Direction.DOWN, thisChess, x, y);
        System.out.println("|" + top2Down);
        if (top2Down >= 5) {
            win(thisChess);
            return;
        }

        int topLeft2RightDown = 1 + countChessNum(Direction.TOP_LEFT, thisChess, x, y) + countChessNum(Direction.RIGHT_DOWN, thisChess, x, y);
        System.out.println("\\" + topLeft2RightDown);
        if (topLeft2RightDown >= 5) {
            win(thisChess);
            return;
        }

        int topRight2DownLeft = 1 + countChessNum(Direction.TOP_RIGHT, thisChess, x, y) + countChessNum(Direction.DOWN_LEFT, thisChess, x, y);
        System.out.println("/" + topRight2DownLeft);
        if (topRight2DownLeft >= 5) {
            win(thisChess);
        }
    }

    // 胜利之后的处理函数
    private void win(Chess thisChess) {
        isOtherOK = false; // 标记游戏结束，禁止继续落子
        // 创建并显示获胜提示对话框
        Alert alert = new Alert(Alert.AlertType.INFORMATION, thisChess == Chess.BLACK ? "黑棋获胜！" : "白棋获胜", ButtonType.OK);
        alert.show();
        currentChess = Chess.BLACK;
        // 设置对话框关闭后的回调逻辑
        alert.setOnCloseRequest(event -> {
            cleanChessBoard();
            if (netType == NetType.CLIENT) {
                client.sendMessage(buildMessage(HEAD_GAME, BODY_OK));
            } else {
                server.sendMessage(buildMessage(HEAD_GAME, BODY_OK));
            }
            game = new Chess[21][21];
            taContent.setText("[系统]新的一局开始了！\n");
        });
    }

    // 计数连续的相同棋子数
    private int countChessNum(Direction direction, Chess thisChess, int x, int y) {
        int num = 0;
        switch (direction) {
            case TOP_LEFT:
                if (x - 1 >= 0 && y - 1 >= 0 && thisChess == game[x - 1][y - 1]) {
                    num++;
                    num += countChessNum(direction, thisChess, x - 1, y - 1);
                }
                break;
            case TOP:
                if (y - 1 >= 0 && thisChess == game[x][y - 1]) {
                    num++;
                    num += countChessNum(direction, thisChess, x, y - 1);
                }
                break;
            case TOP_RIGHT:
                if (x + 1 <= 20 && y - 1 >= 0 && thisChess == game[x + 1][y - 1]) {
                    num++;
                    num += countChessNum(direction, thisChess, x + 1, y - 1);
                }
                break;
            case RIGHT:
                if (x + 1 <= 20 && thisChess == game[x + 1][y]) {
                    num++;
                    num += countChessNum(direction, thisChess, x + 1, y);
                }
                break;
            case RIGHT_DOWN:
                if (x + 1 <= 20 && y + 1 <= 20 && thisChess == game[x + 1][y + 1]) {
                    num++;
                    num += countChessNum(direction, thisChess, x + 1, y + 1);
                }
                break;
            case DOWN:
                if (y + 1 <= 20 && thisChess == game[x][y + 1]) {
                    num++;
                    num += countChessNum(direction, thisChess, x, y + 1);
                }
                break;
            case DOWN_LEFT:
                if (x - 1 >= 0 && y + 1 <= 20 && thisChess == game[x - 1][y + 1]) {
                    num++;
                    num += countChessNum(direction, thisChess, x - 1, y + 1);
                }
                break;
            case LEFT:
                if (x - 1 >= 0 && thisChess == game[x - 1][y]) {
                    num++;
                    num += countChessNum(direction, thisChess, x - 1, y);
                }
                break;
        }
        return num;
    }

    // 绘制棋子
    private void drawChess(Chess chess, Position p) {
        double x = p.x * gapX + broadPadding;
        double y = p.y * gapY + broadPadding;
        switch (chess) {
            case BLACK:
                gc.setFill(Color.BLACK);
                gc.fillOval(x - chessSize / 2, y - chessSize / 2, chessSize, chessSize);
                break;
            case WHITE:
                gc.setFill(Color.WHITE);
                gc.fillOval(x - chessSize / 2, y - chessSize / 2, chessSize, chessSize);
                break;
        }
    }

    // 悔棋
    private void removeChess() {
        double x = lastPostion.x * gapX + broadPadding;
        double y = lastPostion.y * gapY + broadPadding;
        gc.setFill(colorChessboard);
        gc.fillOval(x - chessSize / 2, y - chessSize / 2, chessSize, chessSize);

        gc.strokeLine(x - chessSize / 2, y, x + chessSize / 2, y);
        gc.strokeLine(x, y - chessSize / 2, x, y + chessSize / 2);
        game[lastPostion.x][lastPostion.y] = null;
    }

    // 棋盘绘制
    public void initialize() {
        gc = canvas.getGraphicsContext2D();
        gapX = (canvas.getWidth() - broadPadding * 2) / 20;
        gapY = (canvas.getWidth() - broadPadding * 2) / 20;
        System.out.println();
        chessSize = gapX * 0.8;
        cleanChessBoard();
        btnUndo.setDisable(true);
        try {
            lbIP.setText("本机IP：" + InetAddress.getLocalHost().getHostAddress());
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }

    //棋盘清空
    private void cleanChessBoard() {
        gc.setFill(colorChessboard);
        gc.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());

        gc.setStroke(colorLine);
        for (int i = 0; i <= 20; i++) {
            gc.strokeLine(i * gapX + broadPadding, broadPadding, i * gapX + broadPadding, canvas.getHeight() - broadPadding);
            gc.strokeLine(broadPadding, i * gapY + broadPadding, canvas.getWidth() - broadPadding, i * gapY + broadPadding);
        }

        gc.setFill(colorMark);
        gc.setFont(Font.font(broadPadding / 2));
        for (int i = 0; i <= 20; i++) {
            gc.fillText(markX[i], i * gapX + broadPadding - 5, broadPadding - 5);
            gc.fillText(markX[i], i * gapX + broadPadding - 5, canvas.getHeight() - 5);
            gc.fillText(markY[i], 5, gapY * i + broadPadding + 5);
            gc.fillText(markY[i], canvas.getWidth() - broadPadding + 5, gapY * i + broadPadding + 5);
        }
    }

    // 启动服务器按钮控制器
    @FXML
    protected void handleStartServer(ActionEvent event) {
        server = NetService.getInstance(NetType.SERVER);
        server.startServer();
        server.setNetStateChangeListener(this); // 设置网络状态改变监听器(当前对象为监听器)
        netType = NetType.SERVER;
    }

    // 连接到服务器按钮控制器
    @FXML
    protected void handleConnectClicked(ActionEvent event) {

        if (tfIP.getText().matches("(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)")) {
            client = NetService.getInstance(NetType.CLIENT);
            client.setNetStateChangeListener(this);
            client.connectToServer(tfIP.getText());
            netType = NetType.CLIENT;
        }
    }

    // 发送按钮控制器
    @FXML
    protected void handleSendClicked(ActionEvent event) {
        if (tfMessage.getText().length() > 0) {
            String message = buildMessage(HEAD_MSG, tfMessage.getText());
            if (netType == NetType.SERVER) {
                server.sendMessage(message);
                taContent.appendText("[玩家A]" + tfMessage.getText() + "\n");
            } else if (netType == NetType.CLIENT) {
                client.sendMessage(message);
                taContent.appendText("[玩家B]" + tfMessage.getText() + "\n");
            }
        }
        tfMessage.setText("");
    }

    // 悔棋按钮控制器
    @FXML
    protected void handleUndoClicked(ActionEvent e) {
        btnUndo.setDisable(true);
        if (netType == NetType.SERVER) {
            String message = buildMessage(HEAD_UNDO, "[玩家A]");
            server.sendMessage(message);
            taContent.appendText("[玩家A]请求悔棋\n");
        } else if (netType == NetType.CLIENT) {
            String message = buildMessage(HEAD_UNDO, "[玩家B]");
            client.sendMessage(message);
            taContent.appendText("[玩家B]请求悔棋\n");
        }
    }

    // 处理客户端连接成功的回调方法
    @Override
    public void onConnect() {
        System.out.println("some one connected");
        server.sendMessage(buildMessage(HEAD_NET, BODY_OK));
        taContent.appendText("[系统]玩家B已连接！\n");// 更新聊天记录，提示玩家B已连接
        // 启用聊天功能（解禁输入框和发送按钮）
        tfMessage.setDisable(false);
        btnSend.setDisable(false);
        taContent.appendText("[系统]玩家A执黑棋，先走\n");//  聊天框提示游戏规则
        currentChess = Chess.BLACK;
    }

    // 网络消息处理的核心回调方法
    @Override
    public void onMessage(String message) {
        System.out.println(message);
        String[] msgArray = message.split(":"); // 获取消息头和消息体
        switch (msgArray[0]) { // 判断消息头
            case HEAD_NET: // 处理网络连接消息
                if (msgArray[1].equals(BODY_OK)) {
                    taContent.appendText("[系统]已连接到玩家A！\n");
                    // 启用聊天功能，禁用连接相关按钮（防止重复连接）
                    tfMessage.setDisable(false);
                    btnSend.setDisable(false);
                    tfIP.setDisable(true);
                    btnStart.setDisable(true);
                    btnConnect.setDisable(true);
                    taContent.appendText("[系统]玩家B执白棋，请等待玩家A先走\n");
                }
                break;
            case HEAD_MSG: //  处理聊天消息
                // 拼接消息内容
                StringBuilder msgContent = new StringBuilder();
                for (int i = 1; i < msgArray.length; i++) {
                    msgContent.append(msgArray[i]);
                    if (i + 1 < msgArray.length) {
                        msgContent.append(':');
                    }
                }
                // 根据当前角色，显示发送方（玩家A/玩家B）和消息内容
                if (netType == NetType.SERVER) {
                    taContent.appendText("[玩家B]" + msgContent.toString() + "\n");
                } else if (netType == NetType.CLIENT) {
                    taContent.appendText("[玩家A]" + msgContent.toString() + "\n");
                }
                break;
            case HEAD_CHESS: //处理走棋消息
                btnUndo.setDisable(true);
                int x = Integer.parseInt(msgArray[1]);
                int y = Integer.parseInt(msgArray[2]);
                Position p = new Position(x, y);
                lastPostion = p;
                // 服务器收到客户端的走棋消息
                if (netType == NetType.SERVER) {
                    taContent.appendText("[玩家B]走子：" + markX[x] + "," + markY[y] + "\n");
                    drawChess(Chess.WHITE, p);
                    game[p.x][p.y] = Chess.WHITE;
                    currentChess = Chess.BLACK;
                    checkWinner(p.x, p.y);
                }
                // 客户端收到服务器的走棋消息
                else if (netType == NetType.CLIENT) {
                    taContent.appendText("[玩家A]走子：" + markX[x] + "," + markY[y] + "\n");
                    drawChess(Chess.BLACK, p);
                    game[p.x][p.y] = Chess.BLACK;
                    currentChess = Chess.WHITE;
                    checkWinner(p.x, p.y);
                }
                break;
            case HEAD_GAME: // 处理游戏状态消息
                isOtherOK = true;
                break;
            case HEAD_UNDO: // 处理悔棋消息
                // 情况1：收到对方的悔棋同意消息（"undo:ok"）
                if (msgArray[1].equals(BODY_OK)) {
                    if(netType==NetType.SERVER) {
                        taContent.appendText("[玩家B]同意悔棋！\n");
                        currentChess = Chess.BLACK;
                    }else if(netType==NetType.CLIENT){
                        taContent.appendText("[玩家A]同意悔棋！\n");
                        currentChess = Chess.WHITE;
                    }
                    removeChess();
                }
                // 情况2：收到对方的悔棋拒绝消息（"undo:no"）
                else if (msgArray[1].equals(BODY_NO)) {
                    if(netType==NetType.SERVER) {
                        taContent.appendText("[玩家B]拒绝悔棋！\n");
                    }else if(netType==NetType.CLIENT){
                        taContent.appendText("[玩家A]拒绝悔棋！\n");
                    }
                }
                // 情况3：收到对方的悔棋请求（如"undo:[主机]"）
                else {
                    taContent.appendText(msgArray[1] + "请求悔棋\n");
                    Alert alert = new Alert(Alert.AlertType.CONFIRMATION, "对方请求悔棋，请选择！", ButtonType.NO, ButtonType.OK);
                    alert.setOnCloseRequest(event -> {
                        if (alert.getResult().getButtonData() == ButtonBar.ButtonData.OK_DONE) {
                            String msg = buildMessage(HEAD_UNDO, BODY_OK);
                            if (netType == NetType.SERVER) {
                                server.sendMessage(msg);
                                taContent.appendText("[玩家A]同意悔棋！\n");
                                currentChess = Chess.WHITE;
                            } else if (netType == NetType.CLIENT) {
                                client.sendMessage(msg);
                                taContent.appendText("[玩家B]同意悔棋！\n");
                                currentChess = Chess.BLACK;
                            }
                            removeChess();
                        } else {
                            String msg = buildMessage(HEAD_UNDO, BODY_NO);
                            if (netType == NetType.SERVER) {
                                server.sendMessage(msg);
                                taContent.appendText("[玩家A]拒绝悔棋！\n");
                            } else if (netType == NetType.CLIENT) {
                                client.sendMessage(msg);
                                taContent.appendText("[玩家B]拒绝悔棋！\n");
                            }
                        }
                    });
                    alert.show();
                }
                break;
        }
    }

    // 处理网络连接断开的回调方法
    @Override
    public void onDisconnect() {
        Alert alert = new Alert(Alert.AlertType.ERROR, "连接已断开！", ButtonType.OK);
        alert.setOnCloseRequest(event -> System.exit(0));
        alert.show();
    }

    // 处理服务器连接成功的回调方法
    @Override
    public void onServerOK() {
        System.out.println("server OK");
        taContent.appendText("[系统]建主成功！\n");
        btnStart.setDisable(true);
        btnConnect.setDisable(true);
        tfIP.setDisable(true);
    }

    private class Position {
        int x;
        int y;
        Position(int x, int y) {
            this.x = x;
            this.y = y;
        }
        @Override
        public String toString() {
            return x + ":" + y;
        }
    }
}